package com.zmc.lostfound.post.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zmc.lostfound.common.constant.PostConstant;
import com.zmc.lostfound.common.exception.MyException;
import com.zmc.lostfound.common.utils.PageResult;
import com.zmc.lostfound.common.utils.Result;
import com.zmc.lostfound.common.utils.redis.RedisCacheUtil;
import com.zmc.lostfound.post.dao.PostDao;
import com.zmc.lostfound.post.dao.PostReviewDao;
import com.zmc.lostfound.post.entity.PostEntity;
import com.zmc.lostfound.post.entity.PostReviewEntity;
import com.zmc.lostfound.post.service.PostReviewService;
import com.zmc.lostfound.post.vo.PostReviewQueryVO;
import com.zmc.lostfound.post.vo.PostReviewSaveVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

import static com.zmc.lostfound.common.constant.RabbitMqConstant.POST_EXCHANGE;
import static com.zmc.lostfound.common.constant.RabbitMqConstant.POST_SAVE_KEY;
import static com.zmc.lostfound.common.constant.RedisConstant.CACHE_POST_DETAIL_KEY_PREFIX;

/**
 * @author WJS
 * @description 帖子审核业务接口
 * @email 2869581855@qq.com
 * @date 2023-07-05 15:49:44
 */
@Service
public class PostReviewServiceImpl extends ServiceImpl<PostReviewDao, PostReviewEntity> implements PostReviewService {

    private final PostDao postDao;

    private final ThreadPoolExecutor threadPoolExecutor;

    private final RedisCacheUtil redisCacheUtil;

    private final RabbitTemplate rabbitTemplate;

    public PostReviewServiceImpl(PostDao postDao, ThreadPoolExecutor threadPoolExecutor, RedisCacheUtil redisCacheUtil, RabbitTemplate rabbitTemplate) {
        this.postDao = postDao;
        this.threadPoolExecutor = threadPoolExecutor;
        this.redisCacheUtil = redisCacheUtil;
        this.rabbitTemplate = rabbitTemplate;
    }

    /**
     * 多条件查询审核信息
     *
     * @param postReviewQueryVO 分页参数
     * @return PageResult
     */
    @Override
    public PageResult queryPage(PostReviewQueryVO postReviewQueryVO) {
        Integer pageNo = postReviewQueryVO.getPageNo();
        Integer pageSize = postReviewQueryVO.getPageSize();
        Page<PostReviewEntity> page = new Page<>(pageNo, pageSize);
        QueryWrapper<PostReviewEntity> queryWrapper = new QueryWrapper<>();
        Long postId = postReviewQueryVO.getPostId();
        Long userId = postReviewQueryVO.getUserId();
        Integer reviewStatus = postReviewQueryVO.getReviewStatus();
        queryWrapper
                .eq(postId != null, "post_id", postId)
                .eq(userId != null, "user_id", userId)
                .eq(reviewStatus != null, "review_status", reviewStatus)
                .orderByAsc("review_status")
                .orderByAsc("id");
        return new PageResult(this.page(page, queryWrapper));
    }

    /**
     * 按id查询审核信息
     *
     * @param id 审核信息id
     * @return PostReviewEntity
     */
    @Override
    public PostReviewEntity queryInfoById(Long id) {
        if (id == null || id <= 0) {
            MyException.throwException("查询失败: id不能为null且必须大于0");
        }
        return this.getById(id);
    }

    /**
     * 新增审核信息
     *
     * @param postReviewSaveVO 举报信息新增/修改请求体
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result insertPostReview(PostReviewSaveVO postReviewSaveVO) {
        PostReviewEntity postReviewEntity = BeanUtil.copyProperties(postReviewSaveVO, PostReviewEntity.class);
        // 设置默认审核状态: 未审核
        if (postReviewSaveVO.getReviewStatus() == null) {
            postReviewEntity.setReviewStatus(PostConstant.PostReviewEnum.NOT_REVIEW.getCode());
        }
        if (!this.save(postReviewEntity)) {
            MyException.throwException("新增审核信息失败");
        }
        return Result.ok("新增成功");
    }

    /**
     * 修改审核信息
     *
     * @param postReviewSaveVO 审核信息新增/修改请求体
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result updatePostReview(PostReviewSaveVO postReviewSaveVO) {
        // 1.修改审核记录的审核状态
        CompletableFuture<Void> postReviewFuture = CompletableFuture.runAsync(() -> {
            PostReviewEntity postReviewEntity = BeanUtil.copyProperties(postReviewSaveVO, PostReviewEntity.class);
            if (!this.updateById(postReviewEntity)) {
                MyException.throwException("审核信息修改失败");
            }
        }, threadPoolExecutor);
        // 2.修改帖子的审核状态
        CompletableFuture<Void> postFuture = CompletableFuture.runAsync(() -> {
            if (postDao.updateById(PostEntity.builder()
                    .id(postReviewSaveVO.getPostId())
                    .reviewStatus(postReviewSaveVO.getReviewStatus())
                    .build()) <= 0) {
                MyException.throwException("帖子审核状态修改失败");
            }
            // 2.1删除redis缓存
            redisCacheUtil.deleteByKey(CACHE_POST_DETAIL_KEY_PREFIX + postReviewSaveVO.getPostId());
            // 2.2发送消息到post.topic交换机，实现MySQL与ES的数据同步
            rabbitTemplate.convertAndSend(POST_EXCHANGE, POST_SAVE_KEY, postReviewSaveVO.getPostId());
        }, threadPoolExecutor);
        CompletableFuture.allOf(postReviewFuture, postFuture).join();
        return Result.ok("修改成功");
    }

    /**
     * 按主键id删除审核信息
     *
     * @param id 审核信息id
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result deleteById(Long id) {
        if (id == null || id <= 0) {
            MyException.throwException("删除失败: id不能为null且必须大于0");
        }
        this.removeById(id);
        return Result.ok("删除成功");
    }

    /**
     * 按帖子id批量删除审核信息
     *
     * @param postId 帖子id
     * @return Result
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Result deleteBatchByPostId(Long postId) {
        if (postId == null || postId <= 0) {
            MyException.throwException("删除失败: 帖子id不能为null且必须大于0");
        }
        this.remove(new QueryWrapper<PostReviewEntity>().eq("post_id", postId));
        return Result.ok("删除成功");
    }

}